/*
 * Created by SharpDevelop.
 * User: Administrador
 * Date: 28/01/2008
 * Time: 07:19 p.m.
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using NUnit.Framework;

namespace ModeloDatos
{
	/// <summary>
	/// Description of ProgramaJava.
	/// </summary>
	public interface SeparableJava{
		void agregarParte(string codigo);
	}
	
	public class CosasJava{
		public static void separarPartes(SeparableJava destino, string codigo){
			string s=codigo;
			Regex principio=new Regex("[^;{]*(;|{)");
			Regex siguientes=new Regex("[^}]*}");
			Match m;
			while(s.Length>0){
				m=principio.Match(s);
				Assert.AreEqual(0,m.Index,m.Value,"la regexp tiene que tomar todo desde el principio");
				int posFinal=m.Length;
				if(posFinal==0){
					posFinal=s.Length;
				}
				string parte=s.Substring(0,posFinal);
				s=s.Remove(m.Index,posFinal);
				while(!Otras.llavesBalanceadas(parte) && s.Length>0){
					m=siguientes.Match(s);
					Assert.AreEqual(0,m.Index,m.Value,"la regexp tiene que tomar todo desde el principio");
					posFinal=m.Length;
					if(posFinal==0){
						posFinal=s.Length;
					}
					parte+=s.Substring(0,posFinal);
					s=s.Remove(m.Index,posFinal);
				}
				destino.agregarParte(parte);
			}
		}
	}
	
	public class ProgramaJava:SeparableJava{
		public const string rxComentario="/(\\*([^*]*(\\*+[^/*])?)*\\*+/)|(/[^\n]*\n)";
		public const string rxBlancos="[ \t\n\r]+";
		public const string rxBlancoSigno=" ([()<>{},;.=+!#])";
		public const string rxSignoBlanco="([()<>{},;.=+!#]) ";
		System.Collections.Generic.List<ClaseJava> clases;
		public static string normalizar(string anormal){
			return Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(
							     anormal
			 					 ,rxComentario," ")
			                     ,rxBlancos," ")
			 					 ,rxBlancoSigno,"$1")
			 					 ,rxSignoBlanco,"$1")
				.Trim();
		}
		public ProgramaJava(string codigo){
			clases=new System.Collections.Generic.List<ClaseJava>();
			CosasJava.separarPartes(this,normalizar(codigo));
		}
		public void agregarParte(string parte){
			clases.Add(new ClaseJava(parte));
		}
		public string debugDump(){
			StringBuilder rta=new StringBuilder(" ");
			foreach(ClaseJava clase in clases){
				rta.Append(clase.debugDump()+"++");
			}
			return rta.ToString();
		}
		public ProgramaJava canonizar(){
			foreach(ClaseJava clase in clases){
				clase.canonizar();
			}
			return this;
		}
		public override string ToString(){
			StringBuilder rta=new StringBuilder();
			foreach(ClaseJava clase in clases){
				rta.AppendLine(clase.ToString());
			}
			return rta.ToString();
		}
	}
	
	public class ClaseJava:SeparableJava{
		string definicion,pie;
		ArrayList miembros;
		public ClaseJava(string codigo){
			miembros=new ArrayList();
			Regex principio=new Regex("[^;{]*(;|{)");
			Match m=principio.Match(codigo);
			if(m.Success){
				definicion=codigo.Substring(0,m.Length);
				if(codigo[m.Length-1]!=';'){
					Regex rxFinal=new Regex("}[^}]*", RegexOptions.RightToLeft);
					Match lugarFinal=rxFinal.Match(codigo);
					int posFinal=m.Length;
					if(posFinal==0){
						posFinal=codigo.Length;
					}
					CosasJava.separarPartes(this,codigo.Substring(posFinal,lugarFinal.Index-posFinal));
					pie=codigo.Substring(lugarFinal.Index);
				}
			}else{
				definicion="error en parseo de clase:";
				pie=codigo;
			}
		}
		public void agregarParte(string parte){
			miembros.Add(parte);
		}
		public string debugDump(){
			StringBuilder rta=new StringBuilder(definicion+"##");
			foreach(string parte in miembros){
				rta.Append(parte+"!!");
			}
			rta.Append(pie);
			return rta.ToString();
		}
		public ClaseJava canonizar(){
			miembros.Sort();
			return this;
		}
		public override string ToString(){
			StringBuilder rta=new StringBuilder(definicion);
			foreach(string parte in miembros){
				rta.AppendLine(parte);
			}
			rta.AppendLine(pie);
			return rta.ToString();
		}
	}
}
